package crypto;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;


import utility.VDiskAPIUtility;

public class DESFileManager implements IFileManager {

	private final static String algorithm = "DES";
	private final static int keyLength = 56;
	private static KeyGenerator keygenerator;
	private static Key key;
	private static Cipher cipher;

	public static boolean init() {
		try {
			if (cipher == null)
				cipher = Cipher.getInstance(algorithm);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Encryption Init Failure");
			return false;
		}
	}

	public static void generateKey() {
		try {
			keygenerator = KeyGenerator.getInstance(algorithm);
			keygenerator.init(keyLength);
			key = keygenerator.generateKey();
			saveKey();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}

	}

	public static void saveKey() {
		try {
			FileOutputStream fosKey = new FileOutputStream("key");
			ObjectOutputStream oos = new ObjectOutputStream(fosKey);
			oos.writeObject(key);
			oos.close();
			fosKey.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void loadKey() {
		try {
			FileInputStream fisKey = new FileInputStream("key");
			ObjectInputStream oisKey = new ObjectInputStream(fisKey);
			key = (Key) oisKey.readObject();
			oisKey.close();
			fisKey.close();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public byte[] decryptBuffer(byte[] buffer, int length) {
		return buffer;
	}

	@Override
	public String decryptName(String name) {
		try {
			cipher.init(Cipher.DECRYPT_MODE, key);
			byte[] decryptedDir = cipher
					.doFinal(VDiskAPIUtility.hex2byte(name));
			return new String(decryptedDir);
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Decrypt Dir Fail");
			return null;
		}
	}

	@Override
	public byte[] encryptBuffer(byte[] buffer, int length) {
		return buffer;
	}

	@Override
	public String encryptName(String name) {
		try {
			cipher.init(Cipher.ENCRYPT_MODE, key);
			byte[] encryptedDir = cipher.doFinal(name.getBytes());
			return VDiskAPIUtility.byte2hex(encryptedDir);
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Encrypt Dir Fail");
			return null;
		}
	}

	@Override
	public void encryptFile(InputStream in, OutputStream out) {
		try {
			byte[] read = new byte[cipher.getBlockSize()];
			int readNum;
			byte[] write;
			cipher.init(Cipher.ENCRYPT_MODE, key);
			while ((readNum = in.read(read)) != -1) {
				write = cipher.update(read, 0, readNum);
				out.write(write);
			}
			out.write(cipher.doFinal());
			System.out.println("Encrypt File Success!");
			out.flush();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	@Override
	public void decryptFile(InputStream in, OutputStream out) {
		try {
			byte[] read = new byte[cipher.getBlockSize()];
			int readNum;
			cipher.init(Cipher.DECRYPT_MODE, key);
			byte[] write;
			while ((readNum = in.read(read)) != -1) {
				write = cipher.update(read, 0, readNum);
				out.write(write);
			}
			out.write(cipher.doFinal());
			System.out.println("Decrypt File Success!");
			out.flush();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}
